声明

本文是学习github5.com 网站的报告而整理的学习笔记,分享出来希望更多人受益,如果存在侵权请及时联系我们

1 范围

本标准规定了C/C++ 语言源代码漏洞测试的测试总则和测试内容。

本标准适用于开发方或第三方机构的测试人员利用自动化静态分析工具开展的C/C++
语言源代 码漏洞测试活动,C/C++
语言的程序设计和编码人员以及源代码漏洞测试工具的设计人员也可参考

使用。

2 规范性引用文件

下列文件对于本文件的应用是必不可少的。凡是注日期的引用文件,仅注日期的版本适用于本文

件。凡是不注日期的引用文件,其最新版本(包括所有的修改单)适用于本文件。

GB/T 11457 信息技术 软件工程术语

GB/T 15532—2008 计算机软件测试规范

GB/T 20158—2006 信息技术 软件生存周期过程 配置管理(ISO/IEC TR
15846:1998,IDT)

3 术语和定义

GB/T 11457界定的以及下列术语和定义适用于本文件。

3.1

访 access control

一种保证数据处理系统的资源只能由被授权主体按授权方式进行访问的手段。

[GB/T 25069—2010,定义2.2.1.42]

3.2

attack

在信息系统中,对系统或信息进行破坏、泄露、更改或使其丧失功能的尝试(包括窃取数据)。

[GB/T 25069—2010,定义2.2.1.58]

3.3

密码分组链接 cipher block chaining

对信息加密时,每一密文块在加密时都依赖于前一密文块的方式。

3.4

密文 ciphertext

利用加密技术,经变换,信息内容被隐藏起来的数据。

[GB/T 25069—2010,定义2.2.2.105]

3.5

解密 decryption

将密文转换为明文的处理,即加密对应的逆过程。

[GB/T 25069—2010,定义2.2.2.69]

GB/T 34943—2017

3.6

字典式攻击 dictionary attack

用遍历给定口令或密钥列表的方式对密码系统的攻击。如,使用存储的特定口令值或密钥值列表,

或使用来自自然语言字典中的单词列表。

[GB/T 25069—2010,定义2.2.2.239]

3.7

域名服务器(DNS) 欺骗 domain name
server(DNS)spoofing

攻击者冒充域名服务器的一种欺骗行为。

3.8

加密 encryption

对数据进行密码变换以产生密文的过程。
一般包含一个变换集合,该变换使用一套算法和一套输

入参量。输入参量通常被称为密钥。

[GB/T 25069—2010,定义2.2.2.60]

3.9

硬编码 hard-coding

在软件实现上,把输入或输出的相关参数直接编码在源代码中,而不是从外部来源获得的数据生

成的。

3.10

散列值 hash-value

散列/杂凑函数的输出的比特串。

[GB/T 25069—2010,定义2.2.2.169]

3.11

散列/杂凑函数 hash function

将比特串映射为固定长度的比特串的函数,该函数满足下列两特性:

——对于给定输出,找出映射为该输出的输入,在计算上是不可行的;

— 对于给定输入,找出映射为同一输出的第二个输入,在计算上是不可行的。

注: 计算上的可行性取决于特定安全要求和环境。

[GB/T 25069—2010,定义2.2.2.166]

3.12

heap

用于动态内存分配的内存空间。

3.13

注入 injection

由于字符过滤不严谨导致的漏洞。

3.14

单向加密 one-way encryption

一种加密,它只产生密文,而不能将密文再生为原始数据。

[GB/T 25069—2010,定义2.2.2.9]

3.15

最优非对称加密填充 optimal asymmetric encryption
padding

RSA
算法的一种加密填充方案,可将原有的确定性的加密方案转换成一种可能性方案,并能防止

GB/T 34943—2017

密文的部分解密或其他信息泄露。

3.16

填充 padding

对数据串附加额外比特。

[GB/T 25069—2010,定义2.2.2.187]

3.17

口令 password

用于身份鉴别的秘密的字、短语、数字或字符序列,通常是被默记的弱秘密。

[GB/T 25069—2010,定义2.2.2.76]

3.18

明文 plaintext

未加密的信息。

[GB/T 25069—2010,定义2.2.2.135]

3.19

彩虹表 rainbow table

一个用于加密散列函数逆运算的预先计算好的表,常用于破解加密过的密码散列。

3.20

反向域名解析 reverse DNS resolution

通过 IP 地址查询服务器域名。

3.21

盐值 salt

作为单向函数或加密函数的二次输入而加入的随机变量,可用于导出口令验证数据。

3.22

种子 seed

一种用作某一确定性随机比特生成器输入的比特串。 DRBG
的部分状态由种子确定。

[GB/T 25069—2010,定义2.2.2.232]

3.23

敏感信息 sensitive information

由权威机构确定的必须受保护的信息,该信息的泄露、修改、破坏或丢失会对人或事产生可预知的

损害。

[GB/T 25069—2010,定义2.2.4.7]

3.24

源代码漏洞 source code vulnerability

存在于软件源代码中的漏洞。

3.25

漏洞 vulnerability

计算机信息系统在需求、设计、实现、配置、运行等过程中,有意或无意产生的缺陷。这些缺陷以不
同形式存在于计算机信息系统的各个层次和环节之中,如果利用不当,会对计算机信息系统的安全造成

损害,从而影响计算机信息系统的正常运行。

注: 改 写GB/T 28458—2012,定义3.2。

4 缩略语

下列缩略语适用于本文件。

GB/T 34943—2017

DNS: 域名服务器(Domain Name Server)

DRBG: 确定性随机比特生成器(Deterministic Random Bit Generator)

IP:网际协议(Internet Protocol)

PRNG: 伪随机数生成器(Pseudorandom Number Generator)

SQL: 结构化查询语言(Structured Query Language)

5 源代码漏洞测试总则

5.1 源代码漏洞测试目的

源代码漏洞测试的目的是:

a) 发现、定位及解决软件源代码中的漏洞;

b) 为软件产品的安全性测量和评价提供依据。

5.2 源代码漏洞测试过程

5.2.1 概述

源代码作为软件产品的重要组成部分,其测试过程基本等同软件产品的测试过程。本标准遵循
GB/T 15532—2008
的要求将源代码测试过程分为测试策划、测试设计、测试执行和测试总结四个

阶段。

5.2.2 测试策划

测试策划主要对整个源代码漏洞测试的过程进行策划。测试策划应确定测试的目标、范围、依据、
环境和工具,应分析与评估测试风险,并制定应对措施。测试策划应重点明确源代码漏洞测试应划分的
阶段以及各阶段的人员角色、任务、时间和工作成果,形成源代码漏洞测试进度计划表。源代码漏洞测

试进度计划见表1。

1 源代码漏洞测试进度计划

测试阶段

人员角色

任务

时间

工作成果

测试策划

《测试计划》

测试设计

《测试说明》

测试执行

《测试日志》

测试总结

《测试总结报告》

5.2.3 测试设计

测试设计应根据测试目标,结合被测源代码的业务和技术特点,明确测试环境和工具,确定测试需
求、测试方法、测试内容、测试准入条件和测试准出条件。测试方法应采用自动化静态分析工具扫描和
人工分析相结合的方法。 C/C++
语言源代码漏洞测试的测试内容宜包括但不限于以下源代码漏洞

分类:

a) 行为问题;

b) 路径错误;

c) 数据处理;

d) 错误的 API 协议实现;

e) 劣质代码;

GB/T 34943—2017

f) 不充分的封装;

g) 安全功能;

h) Web 问题。

以上8类源代码漏洞分别对应6.1源代码漏洞相关分类。

若被测源代码采用了C/C++
语言的第三方框架,测试人员应根据被测源代码的实际情况在测试
内容中增加第三方框架相关的漏洞。

应设计测试用例。源代码漏洞测试的测试用例应包括但不限于以下要素:

a) 名称和编号;

b) 自动化静态分析工具的操作步骤和参数配置;

c) 自动化静态分析工具的期望操作结果。

5.2.4 测试执行

测试执行包括自动化静态分析工具扫描和人工分析。

应根据测试用例明确的操作步骤,使用自动化静态分析工具执行测试,记录测试执行过程及测试

结果。

应对自动化静态分析工具的测试结果进行人工分析,人工分析宜包括但不限于以下任务:

a)
宜按漏洞类别或漏洞风险级别从高到低的顺序分析扫描得到的所有源代码漏洞;

b) 结合源代码的上下文和业务需求,验证疑似漏洞,筛除误报的源代码漏洞;

c) 与开发人员沟通确认源代码漏洞分析结果。

5.2.5 测试总结

测试总结应对整个源代码漏洞测试过程进行总结,测试总结应包括但不限于以下任务:

a) 核查测试环境、工具、内容、方法和结果是否正确;

b) 确认测试目标和测试需求是否得到满足;

c) 总结测试内容、方法和结果,出具测试报告。

5.3 源代码漏洞测试管理

5.3.1 过程管理

应对源代码漏洞测试的过程进行管理, 一般包括:

a) 提出源代码漏洞测试各个阶段的任务要求和质量要求。

b)
安排对源代码漏洞测试的过程进行质量监督和阶段评审,包括监督和评审所需的环境、设备、
资金和人员,质量监督的记录应形成文档。

c) 对源代码漏洞测试的风险进行管理,提供风险规避所需的相关资源。

d)
提供完成源代码漏洞测试各项任务所需的资源保障。包括测试的环境、工具、资金和人员。

表2给出了源代码漏洞测试的人员配备的参考。

2 源代码漏洞测试人员配备情况表

工作角色

具体职责

测试项目负责人

管理监督测试项目,提供技术指导,获取适当的资源,制定基线,技术协调,负责项目的安全保

密、过程管理和质量管理,负责测试策划和测试总结

测试设计员

开展测试需求分析,确定测试内容、测试方法、测试(软、硬件)环境、测试工具,设计测试用例,

建立测试环境

GB/T 34943—2017

2 (续)

工作角色

具体职责

测试员

执行测试,记录测试过程和结果

测试分析员

对自动化静态分析工具的测试结果进行人工分析

测试系统管理员

对测试环境和资产进行管理和维护

配置管理员

设置、管理和维护测试配置管理数据库

测试评审员

对测试的各个阶段进行评审

注1:当软件的供方实施测试时,配置管理员由软件开发项目的配置管理员承担;当独立的测试组织实施测试

时,需配备测试活动的配置管理员。

注2:一个人可承担多个角色的工作, 一个角色可由多个人承担。

5.3.2 过程评审

5.3.2.1 概述

源代码漏洞测试包括测试策划、测试设计、测试执行和测试总结四个阶段。每个测试阶段结束时应

开展阶段评审。评审的级别和参加人员要求宜根据被测源代码的重要程度而确定。

5.3.2.2 测试策划评审

完成测试策划后,应对测试计划进行评审,形成测试策划评审表。评审的具体内容应包括:

a) 评审测试环境、工具等测试实施条件要素考虑是否全面合理;

b) 评审测试人员分工和进度计划等测试组织要素是否具有可实施性;

c) 评审风险分析是否全面合理以及是否具有可行的应对风险的措施。

5.3.2.3 测试设计评审

完成测试设计后,应对测试说明和测试就绪情况进行评审,形成测试设计评审表。评审的具体内容

应包括:

a) 评审测试需求分析是否合理;

b) 评审测试内容和方法是否符合测试需求;

c) 评审测试用例的操作步骤和参数配置是否详细、正确、可实施;

d) 评审测试用例的期望结果描述是否准确;

e) 评审测试人员、环境和工具是否齐备并符合要求。

5.3.2.4 测试执行评审

完成测试执行后,应对测试日志进行评审,形成测试执行评审表。评审的具体内容应包括:

a) 评审测试用例执行是否完整;

b) 评审操作结果是否真实有效;

c) 评审操作结果描述是否清晰、准确;

d) 对于与预期结果不一致的操作结果,评审是否记录了详细的问题现象;

e) 评审人工分析的结果是否正确。

5.3.2.5 测试总结评审

完成测试总结后,应对测试总结报告进行评审,形成测试总结评审表。评审的具体内容应包括:

GB/T 34943—2017

a) 评审测试需求和测试目标是否全面准确完成;

b) 评审测试结论与测试结果追溯的合理性;

c) 评审是否具备测试结束条件;

d) 评审测试风险规避是否合理。

5.3.3 配置管理

应按照软件配置管理的要求,将测试过程中产生的各种软件工作产品纳入配置管理。配置管理要

求见GB/T 20158—2006。

5.4 源代码漏洞测试工具

选择源代码漏洞测试工具应首先明确 GB/T 15532—2008
中4.8.2的要求,重点应考虑工具的漏报

率和误报率,可通过调查或比较的方式评估工具的漏报率和误报率。

选择的源代码漏洞测试工具应覆盖但不限于本标准的源代码漏洞测试内容,测试前应对工具的漏

洞规则库和测试引擎进行必要的升级和维护。

注:选择源代码漏洞测试工具建议结合项目的具体需求。如可行,首先考虑选用商业的自动化静态分析工具。若
条件不具备,也可选用开源的自动化静态分析工具。

5.5 源代码漏洞测试文档

源代码漏洞测试文档一般包括测试计划、测试说明、测试日志和测试总结报告。源代码漏洞测试文

档宜单独出具,也可与其他测试类型出具的测试文档合并。测试文档的基本内容参见附录
A 的案例。

6 源代码漏洞测试内容

6.1 源代码漏洞分类

本标准根据软件开发中常用的概念来组织 C/C++
语言源代码漏洞的类别,具体分为如下8个

类别:

a) 行为问题—— 由于应用程序的意外行为而引发的漏洞。

b) 路径错误——不恰当的处理访问路径而引发的漏洞。

c) 数据处理— 处理数据的功能中发现的漏洞。

d) 错误的 API 协议实现—— 由于软件未按预期用法使用API 而引发的漏洞。

e) 劣质代码—— 由于软件编写不规范导致潜在的漏洞。

f) 不充分的封装——未充分封装关键数据或功能而引发的漏洞。

g)
安全功能——软件安全功能如身份鉴别、访问控制、机密性、密码学和特权管理等相关的漏洞。

h) Web 问题——Web 技术相关的漏洞。

C/C++ 语言各源代码漏洞的名称及其所属的类别参见附录 B。

6.2 源代码漏洞说明

6.2.1 行为问题

6.2.1.1 不可控的内存分配

漏洞描述:内存分配的大小受外部控制的输入数据影响,且程序没有指定内存分配大小的上限。

漏洞风险:攻击者可以使程序分配大量的内存,程序可能会因为内存资源不足而崩溃。

修复或规避建议:在程序中指定内存分配大小的上限,在分配内存前对要分配的内存大小进行验

证,确保要分配的内存大小不超过上限。

GB/T 34943—2017

示例1 :不规范用法

void example fun(int length)//length为用户的输入数据

char x buffer;

if(length<0)//没有验证length是否超出内存分配的上限

return 0;

buffer =(char)malloc(sizeof(char)*length);

free(buffer);

buffer = NULL;

示例2: 规范用法之一

const int MAX LENGTH=1024; //指定内存分配的上限或动态判断剩余内存大小自动分配

void example fun(int length)//length为用户的输入数据

char * buffer:

if(length>MAX LENGTH || length<0)//对length进行验证

return 0;

buffer =(char)malloc(sizeof(char)*length);

if(buffer!= NULL)

···

free(buffer);

buffer = NULL;

6.2.2 路径错误

6.2.2.1 不可信的搜索路径

漏洞描述:程序使用关键资源时没有指定资源的路径,而是依赖操作系统去搜索资源。

漏洞风险:攻击者可以在搜索优先级更高的文件夹中放入相同名称的资源,程序会使用攻击者控制
的资源。

修复或规避建议:使用关键资源时指定资源所在的路径。

示例1:不规范用法

#include<stdio.h)

#include<string.h)

void example fun(void)

//攻击者可在搜索优先级更高的文件夹中放入和dir同名的恶意程序导致command的内容无法正确执行 system(command);//本例中command ="dir.exe E:\\data"

·

GB/T 34943—2017

示例2 :规范用法之一

#include<stdio.h)

#include<string.h)

void example fun(void)

//PATH是存放操作系统中dir命令所在完整路径的常量,本例中PATH="C:\WINDOWS\\system32\\"

char cmd[MAX SIZE]=PATH; //使用完整路径确保command的内容能正确执行

strcat(cmd,command);//本例中command="dir.exe E:\\data"

system(cmd);

6.2.3 数据处理

6.2.3.1 相对路径遍历

漏洞描述:路径名受外部控制的输入数据影响,且程序没有使能够解析到目录外位置的字符序列

(如"..")失效。

漏洞风险:攻击者可以通过输入能够解析到目录外位置的字符序列来访问限制目录之外的文件或

目录。

修复或规避建议:在构建路径名前对输入数据进行验证,确保外部输入仅包含允许的构成路径名的

字符。

示例 1:不规范用法

#include<stdio.h)

#include<string.h)

void example fun(const char* filename)//filename为用户的输入数据,不超过10个字符

FILE *file; //待访问的文件

char path[32]="C:\\data\\";//待访问文件的路径

strcat(path,filename);//filename可能包含".."字符序列导致访问"C:\\data\\"目录之外的文件

file = fopen(path,"r");

·

示例2 :规范用法之一

#include<stdio.h)

#include<string.h)

int verification(const char* str)//验证str是否合法,函数仅供参考

{

//设置白名单

char whitelist[MAX SIZE][16]={"A001.txt","A002.txt",.};

· ·

int flag =0;

int i;

//循环比较str是否在白名单内

for(i=0;i<MAX SIZE;i++)

GB/T 34943—2017

if(strcmp(whitelist[i],str)==0)

{

flag =1;

break;

return flag;

void example fun(const char* filename)//filename为用户的输入数据,不超过10个字符

FILE *file;//待访问的文件

char path[32]="C:\\data\\";//待访问文件的路径

if(verification(filename))

//文件名合法则将路径和文件名组合成完整的文件访问路径

strcat(path, filename);

file = fopen(path,"r");

6.2.3.2 绝对路径遍历

漏洞描述:路径名由外部控制的输入数据决定,且程序没有限制路径名允许访问的目录。

漏洞风险:攻击者可以通过输入路径名来访问任意的文件或目录。

修复或规避建议:在程序中指定允许访问的文件或目录,在访问文件或目录前对路径名进行验证,

确保仅允许访问指定的文件或目录。

1:不规范用法

#include<stdio.h)

#include<string.h)

void example fun(const char* absolutepath)//absolutepath为用户的输入数据

FILE *file;

file = fopen(absolutepath,"r");//攻击者可以访问任意文件或目录

示例2: 规范用法之一

#include(stdio.h)

#include<string.h)

int verification(const charx str)//验证str是否合法,函数仅供参考

//设置白名单

char userlist[MAX SIZE][16]={"A001.txt","A002.txt",.};

GB/T 34943—2017

char whitelist[MAX SIZE][32];

int i;

for(i=0;i<MAX SIZE;i++)

strcpy(whitelist[i],PATH);//PATH是该应用程序允许访问路径的常量,本例中PATH="E:\

Users\\"

strcat(whitelist[i],userlist[i]);

int flag =0;

//循环比较str是否在白名单内

for(i=0;i<MAX SIZE;i++)

if(strcmp(whitelist[i],str)==0)

flag =1;

break;

return flag;

}

void example fun(const char* absolutepath)//absolutepath为用户的输入数据

{

FILE *file;

if(verification(absolutepath))

//路径合法则允许访问文件

file = fopen(absolutepath,"r");

6.2.3.3 命令注入

漏洞描述:使用未经验证的输入数据构建命令。

漏洞风险:攻击者可执行任意命令。

修复或规避建议:在构建命令前对输入数据进行验证,确保输入数据仅能用于构成允许的命令。

示例1:不规范用法

#include <stdio.h>

#include<string.h)

void example fun(char* command)//command为用户输入数据,不超过31个字符

//PATH是存放操作系统中cmd.exe所在完整路径的常量,本例中PATH="C:\WINDOWS\\system32\\"

char cmd[128]= PATH;

strcat(cmd,"cmd.exe /c \"");

GB/T 34943—2017

if(command!= NULL)//未对command进行验证,攻击者可执行delete等恶意命令

strcat(cmd, command);

strcat(emd,"\"");

system(cmd);

示例2: 规范用法之一

#include(stdio.h)

#include<string.h>

int verification(const char* permission, const char* str)//验证str是否合法,函数仅供参考

//设置白名单

char userlist[MAX SIZE][8]={"A001","A002",.};

char whitelist[MAX SIZE][32];

int i;

for(i=0;i<MAX SIZE;i++)

strepy(whitelist[i],permission);

streat(whitelist[i],userlist[i]);

int flag =0;

//循环比较str是否在白名单内

for(i=0;i<MAX SIZE;i++)

if(strcmp(whitelist[i],str)==0)

flag =1;

break;

return flag;

void example fun(char* command)//command为用户输入数据,不超过31个字符

{

//PATH是存放操作系统中cmd.exe所在完整路径的常量,本例中PATH="C:\WINDOWS\\system32\\"

char cmd[128]= PATH;

strcat(cmd,"emd.exe /c \"");

//本例假设用户只有查询权限,QUERY是限制查询目录的字符串常量,本例中QUERY="dir.exe E:\

Users\\"

if(verification(QUERY,command))

//命令合法则允许执行

GB/T 34943—2017

strcat(cmd,command);

strcat(cmd,"\"");

system(cmd);

6.2.3.4 SQL 注入

漏洞描述:使用未经验证的输入数据采用拼接字符串的方式形成 SQL 语句。

漏洞风险:攻击者可输入任何 SQL
语句,实现越权查询数据库的敏感数据、非法修改数据库数据和

提升攻击者的数据库权限等目的。

修复或规避建议:在拼接 SQL
语句前对输入数据进行验证,确保输入数据不包含 SQL 语句的关键

字符;或使用参数化 SQL 查询语句,并将输入数据作为SQL 语句的参数。

示例 1:不规范用法

#include<stdio.h)

#include<string.h)

void sql query(char* name) //name为用户输入数据,不超过10个字符

//本例中userid是仅由字母和数字组成的长度不超过10位的字符串

char sqIQuery[64]="SELECT * FROM CUSTOMER WHERE userid=";

//拼接sql语句前未验证name是否合法

strcat(sqlQuery,name);

strcat(sqlQuery,"");

//在数据库中执行sqlQuery语句

示例2: 规范用法之一

#include<stdio.h)

#include<string.h)

#include<regex.h)

int verification(const char* str) //验证str是否合法,函数仅供参考

{

//设置白名单

char whitelist[MAX SIZE][8]={"A001","A002",.};

int flag =0;

inti=0;

//循环比较str是否在白名单内

for(i=0;i<MAX SIZE;i++)

f(strcmp(whitelist[i],str)==0)

GB/T 34943—2017

flag =1;

break;

return flag;

void sqlquery(char* name)//name为用户输入数据,不超过10个字符

//本例中userid是仅由字母和数字组成的长度不超过10位的字符串

char sqlQuery[64]="SELECT FROM CUSTOMER WHERE userid='";

if(verification(name))//在拼接SQL语句前验证name是否合法

streat(sqlQuery,name);

streat(sqlQuery,"");

//在数据库中执行sqlQuery语句

3:规范用法之一

#include(stdio.h)

#include "stdafx.h"

#include<string.h)

#include<malloc.h>

#include<string〉

using namespace std;

string to legal param(char* param)

string strSql(param);

string returnValue ="";

string::size type pos = 0;

for(inti=0;i<strSql.size();i++)

if (strSql[i]==↑)

returnValue+="";

else

returnValue+= strSql[i];

return returnValue;

void sqlquery(char* name)//name为用户输入数据,不超过10个字符

GB/T 34943—2017

string sqlQuery ="SELECT x FROM CUSTOMER WHERE userid=";

//将参数name转换为合法的SQL字段值

string strName= to legal param(name);

sqlQuery += strName;

sqlQuery+="";

//在数据库中执行sqlQuery语句

6.2.3.5 进程控制

漏洞描述:使用未经验证的输入数据作为动态加载的库的标识符。

漏洞风险:使用未经验证的输入数据作为动态加载的库的标识符使攻击者有机会加载恶意的代

码库。

修复或规避建议:在动态加载库前对输入数据进行验证,确保输入数据仅能用于加载允许加载的代

码库。

示例 1:不规范用法

#include<windows.h)

void load lib(char* libraryName)//libraryName为用户输入数据,不超过15个字符

char path[32]="C:\\";

strcat(path,libraryName);

//使用未经验证的输入数据作为动态加载的库可能导致加载恶意代码库

HANDLE hlib = LoadLibrary(path);

示例2:规范用法之一

#include〈windows.h)

int verification(char*); //验证库文件,通过验证则返回1,否则返回0

void load lib(char* libraryName)//libraryName为用户输入数据,不超过15个字符

char path[32]="C:\\";

if(verification(libraryName)) //判断libraryName是否是合法的库

strcat(path,libraryName);

HANDLE hlib = LoadLibrary(path);

6.2.3.6 缓冲区溢出

漏洞描述:对被分配内存空间之外的内存空间进行读或写操作。

漏洞风险:攻击者可利用缓冲区溢出让系统崩溃或者执行恶意代码。

GB/T 34943—2017

修复或规避建议:在对缓冲区进行读或写时,对读写缓冲区的数据长度进行检查,确保读写的内存

在被分配的内存空间之内。

1:不规范用法

void example fun()

··

char value[11];//本例中假设只允许用户输入10个以下的字符

printf("Enter The Value:");

//攻击者可输入大于10个字符的字符串,覆盖栈原来的返回地址,造成缓冲区溢出

scanf("%s",value);

… ·

示例2: 规范用法之一

void example fun()

char value[11];//本例中假设只允许用户输入10个以下的字符

printf("Enter The Value:");

//从标准输入读取最多10个字符,并保存在value数组中

scanf("%10s",value);

6.2.3.7 使用外部控制的格式化字符串

漏洞描述:printf
函数中的格式化字符串受外部输入数据影响,这可能会导致缓冲区溢出或数据表

示法问题。

漏洞风险:攻击者可输入恶意的格式化字符串造成缓冲区溢出,进而导致系统崩溃或者执行恶意

代码。

修复或规避建议:确保向所有格式字符串函数都传递一个不能由用户控制的静态格式化字符串,并

且向该函数发送正确数量的参数。

示例1:不规范用法

void example fun(char* s) //s 为用户输入数据

printf(s); //s 中可能包含"%n"等格式控制符导致缓冲区溢出

示例2: 规范用法之一

void example fun(char* s)//s为用户输入数据

· ·

printf("%s",s);//传递一个不能由用户控制的静态格式化字符串

. .

GB/T 34943—2017

6.2.3.8 整数溢出

漏洞描述:使用未经验证的整型数据进行算术运算,可能会导致计算结果过大而无法在系统位宽度
范围内存储。

漏洞风险:攻击者可输入过大的数据引发软件崩溃或破坏系统重要内存等安全事件。

修复或规避建议:在对来自用户的整型数据作算术运算前进行验证,确保运算结果不会溢出。

示例1:不规范用法

unsigned int num; //本例中num值为1000

void example fun()

{

… ·

//本例代码假设是运行在32位的系统中,32位系统中指针占4字节,unsigned int最大值是Oxffffffff

unsigned int mrsp = packet get int();//mrsp是来自用户的数据

/*关

攻击者可通过让(mrsp+num)值为0xffffffff/4+1=1073741825,即mrsp=1073740825,造成整型溢出

*(mrsp+num)* sizeof(char*)等效于1073741825*4,溢出后求模后值为4,即为response分配了4字节

的空间

*循环次数为1073740825次,用户数据将覆盖大量的内存空间

**/

char* response = malloc((mrsp+ num)*sizeof(char*));

unsigned int i;

for(i=0;i<mrsp;i++)

response[i]= packet get string();

示例2 :规范用法之一

unsigned int num;//本例中num值为1000

void example fun()

//本例代码假设是运行在32位的系统中

unsigned int mrsp = packet get int();//mrsp是来自用户的数据

if(mrsp>0& .& .UINT MAX- num> mrsp)//运算前验证mrsp

char* response = malloc((mrsp+ num)* sizeof(char*));

unsigned int i;

for(i=0;i<mrsp;i++)

response[i]= packet get string();

GB/T 34943—2017

6.2.3.9 信息通过错误消息泄露

漏洞描述:软件呈现给用户的错误消息中包括与环境、用户或相关数据有关的敏感信息。

漏洞风险:对攻击者而言,敏感信息可能本身就是有价值的信息,或者有助于开展进一步的攻击。

修复或规避建议:确保错误消息中仅含有对目标受众有用的少量细节。

示例1:不规范用法

void write wrong msg(char*); //将错误消息呈现到用户界面

void example fun()

const char* PATH="C:\\config.txt";

File* file = fopen(PATH,"rw");

if(!file)

char msg[128]="Error:";

strcat(msg,PATH);

streat(msg,"does not exist.");

write wrong msg(msg);//输出配置目录的完整路径名

示例2: 规范用法之一

void write wrong msg(char*);//将错误消息呈现到用户界面

void example fun()

{

const char PATH="C:\\config.txt";

File* file = fopen(PATH,"rw");

if(!file)

char msg[128]="Sorry! We will fix the problem soon!";

write wrong msg(msg);//不输出敏感信息

6.2.3.10 信息通过服务器日志文件泄露

漏洞描述:将敏感信息写入服务器日志文件。

漏洞风险:攻击者有机会通过访问日志文件读取敏感信息。

修复或规避建议:慎重考虑写入日志文件信息的隐私性。不要把敏感信息写入日志文件。
示例1 :不规范用法

int is trusted(char*,char*);//判断用户名口令是否正确,均正确则返回1,否则返回0

void write log(charx);//将消息写入日志文件

void data visit(char* username,char* password)//username和password为用户输入数据,均不超过10个

字符

{

GB/T 34943—2017

if(is trusted(username,password)) //用户名和口令正确时调用write log()写入日志

char msg[64];

strcat(msg,username);

strcat(msg," and ");

strcat(msg,password);

strcat(msg," correct!");

write log(msg);//msg中包含敏感信息

//执行访问数据等操作

示例2: 规范用法之一

int is trusted(char*,char*);//判断用户名口令是否正确,均正确则返回1,否则返回0

void write log(char*);//将消息写入日志文件

void data visit(char* username, char* password)//username和password为用户输入数据,均不超过10个 字符

if(is trusted(username, password))

char* msg ="Login success!"; //msg中不包含敏感信息

write log(msg);

//执行访问数据等操作

6.2.3.11 信息通过调试日志文件泄露

漏洞描述:应用程序没有充分限制对用于调试的日志文件的访问。

漏洞风险:调试日志文件通常包含应用程序的敏感信息,攻击者有机会通过访问调试日志文件读取

敏感信息。

修复或规避建议:在产品发布之前移除产生日志文件的代码。

示例 1:不规范用法

void init address book() //地址簿初始化

{

char bookid[8];//地址簿id

char bookpath[64];//地址簿存放路径

···

//生成调试日志

CCLOG("AddressBookID:%s\n",bookid);

CCLOG("Path:%s\n",bookpath);

···

GB/T 34943—2017

示例2: 规范用法之一

void init address book()//地址簿初始化

char bookid[8];//地址簿id

char bookpath[64]; //地址簿存放路径

//程序发布之前将调试代码注释或删除掉

/* CCLOG("AddressBookID:%s\n",bookid);

CCLOG("Path:%s\n",bookpath);

6.2.3.12 未检查的输入作为循环条件

漏洞描述:软件没有对被用于循环条件的输入进行适当的检查。

漏洞风险:攻击者可以让软件循环过多而使软件拒绝服务。

修复或规避建议:规定循环次数的上限,在将用户输入的数据用于循环条件前验证用户输入的数据

是否超过上限。

示例 1:不规范用法

void example fun(int count)//count为用户输入数据

int i;

if(count>0)//未检查count的值是否过大可能导致软件循环过多而使软件拒绝服务

for(i=0;i<count;i++)

示例2: 规范用法之一

int MAX COUNT=1000;//本例中定义循环次数最大为1000次

void example fun(int count)//count为用户输入数据

int i;

if(count>0 &.&.count<=MAX COUNT)//判断循环次数是否不大于最大循环次数

for(i=0;i<count;i++)

GB/T 34943—2017

6.2.4 错误的 API 协议实现

6.2.4.1 堆检查

漏洞描述:使用 realloc()来调整存储敏感信息的缓冲区。

漏洞风险:使用
realloc()来调整存储敏感信息的缓冲区会将敏感信息暴露给攻击者,因为这些信
息并没有从内存中删除掉,攻击者可能使用"堆检查"方法(如内存转储方法)读取堆内存中的敏感

信息。

修复或规避建议:使用realloc()函数前先清空该内存块中的敏感信息。

示例 1:不规范用法

int get memory(char* ptr ,int new size)

ptr = realloc(ptr,new size);//使用realloc()重新分配内存之前未清空该内存块信息

if(ptr)

return 1;

else

return 0;

示例2: 规范用法之一

int get memory(char* ptr ,int new size)

memset(ptr,0,strlen(ptr)); //使用memset()置0

ptr = realloc(ptr,new size);

if(ptr)

return 1;

else

return 0:

6.2.5 劣质代码

6.2.5.1 敏感信息存储于上锁不正确的内存空间

漏洞描述:程序将敏感信息存储在未被锁定或被错误锁定的内存中。

漏洞风险:该敏感信息可能会被虚拟内存管理器从内存写入磁盘的交换文件中,从而使攻击者更容

易访问这些敏感信息。

修复或规避建议:选择恰当的平台保护机制锁定存放敏感信息的内存,并检查方法的返回值确保锁

定操作执行正确。

GB/T 34943—2017

1:不规范用法

#include<stdlib.h>

void example fun(char* parameter)//parameter长度不超过20个字符

char * password ="";//password用于存放敏感信息

password =(char *)malloc(30 * sizeof(char));

if(password!= NULL)

strcpy(password, parameter);//password指向的内存未锁定

2 :规范用法之 一

#include <stdlib.h>

#include(windows.h)

void example fun(char* parameter)//parameter长度不超过20个字符

char * password="";//password用于存放敏感信息

password =(char *)malloc(30* sizeof(char));

if(password!= NULL)

if(VirtualLock(password,30))//锁定password指向的内存,并检查返回值确保锁定操作执行正确

strcpy(password, parameter);

… ·

VirtualUnlock(password,30);//解锁内存

6.2.6 不充分的封装

6.2.6.1 公有函数返回私有数组

漏洞描述:类中定义的私有数组属性在该类的公有函数中被作为返回值返回。

漏洞风险:类中的私有数组作为函数的返回值暴露到了公有区域,存在该私有数组成员在公有区域

被篡改的风险。

修复或规避建议:当私有数组成员的数据需要作为公有函数的返回值时,应返回该私有数组的

副本。

示例 1:不规范用法

class CTest

private:

char secret[MAX SIZE]=“abcd”;

public:

GB/T 34943—2017

char[] get value()

return secret;

2:规范用法之一

class CTest

private;

char

secret[MAX SIZE]=“abcd”;

public:

char

cpy secret[MAX SIZE];

char[] get value()

memcpy(cpy secret,secret,sizeof(secret));//创建私有数组的副本

return cpy secret;

6.2.7 安全功能

6.2.7.1 明文存储口令

漏洞描述:将口令明文存储。

漏洞风险:明文存储口令会降低攻击的难度,攻击者若获得访问口令存储文件的权限,便可轻易获

取口令。

修复或规避建议:尽量避免在容易受攻击的地方存储口令。如果需要,考虑存储口令的加密散列,

以替代明文口令存储。

示例 1:不规范用法

void store password(char*); //将口令存入数据库

void example fun(char* password)

store password(password); //明文存储口令

2:规范用法之一

#include "sha.h"

using namespace CryptoPP;

int encrypt(char* input,char* output) //加密函数,输出参数返回加密后的字符串

SHA256 sha256;

int r= sha256.enc(input,output);//加密算法,对input加密(为确保此处安全,最好使用不可逆加密算法)

GB/T 34943—2017

void store password(char*); //将口令存入数据库

void example fun(char* password)

·

char psw[1024]={0};

intr = encrypt(password,psw); //加密 password

store password(psw); //存储加密后的 psw

··

6.2.7.2 存储可恢复的口令

漏洞描述:采用双向可逆的加密算法加密口令并将口令存储在外部文件或数据库中。

漏洞风险:攻击者有机会通过解密算法对口令进行解密。

修复或规避建议:当业务不需要取已存储的口令进行还原时,使用单向加密算法对口令进行加密并

存储。

示例 1:不规范用法

#include "aes.h"

using namespace CryptoPP;

int encryptor(char* input,char* output)//加密函数,输出参数返回加密后的字符串

AESEncryption aesEncryptor;

int r = aesEncryptor.enc(input,output);//使用双向可逆的AES加密算法

… ·

void store password(char*);//将口令存放到数据库中

void example fun(char* password)

char psw[10247={0};

int r=encryptor(password,psw);//加密password

store password(psw); //存放加密后的psw

··

2 :规范用法之 一

#include "sha.h"

using namespace CryptoPP;

int encrypt(char* input,char* output)//加密函数,输出参数返回加密后的字符串

SHA256 sha256;

int r= sha256.enc(input, output);//使用单向不可逆的SHA256加密算法

void store password(char*);//将口令存放到数据库中

GB/T 34943—2017

void example fun(char* password)

···

char psw[1024]={0};

intr = encryptor(password,psw);//加密password

store password(psw);//存放加密后的psw

6.2.7.3 口令硬编码

漏洞描述:程序代码(包括注释)中包含硬编码口令。

漏洞风险:攻击者可以通过反编译或直接读取二进制代码的方式获取硬编码口令。

修复或规避建议:使用单向不可逆的加密算法对口令进行加密并存储在外部文件或数据库中。

示例 1:不规范用法

int psw is correct(char* password)//判断口令是否正确,是则返回1,不是则返回0

if(strcmp(password,"jk46k643h9gj9iwd63")==0) //代码中包含硬编码口令

return 1;

return 0;

2:规范用法之一

#include "sha.h"

using namespace CryptoPP;

int encryptor(char* input,char* output)//加密函数,输出参数返回加密后的字符串

{

SHA256 sha256;

int r = sha256.enc(input, output);

char* get psw(void);//从数据库获得口令

int psw is correct(char* password)//判断口令是否正确,是则返回1,不是则返回0

·

char* psw = get psw();

char hpsw[1024]={0};

intr = encryptor(password,hpsw);//加密password

if(strcmp(hpsw,psw)==0)//判断加密后得到的hpsw与数据库中存储的psw是否相同

return 1;

return 0:

GB/T 34943—2017

6.2.7.4 敏感信息明文传输

漏洞描述:敏感信息在传输过程中未进行加密。

漏洞风险:攻击者有机会通过在传输过程中截取或复制报文获取敏感信息。

修复或规避建议:发送敏感信息前对敏感信息进行加密或采用加密通道传输敏感信息。

示例 1:不规范用法

void send message(char*);//将传进来的字符串发送出去

void example fun(char* address) //address是用户的敏感信息

send message(address);//传输address前没有进行加密

示例2: 规范用法之一

#include "aes.h"

using namespace CryptoPP;

void send message(char*);//将传进来的字符串发送出去

int encryptor(charx input,char* output) //加密函数,输出参数返回加密后的字符串

AESEncryption aesEncryptor;

int r = aesEncryptor.enc(input,output);

void example fun(char* address)//address是用户的敏感信息

intr = encryptor(address,addr); //加密address

send message(addr); //传输加密得到的addr

6.2.7.5 使用已破解或危险的加密算法

漏洞描述:软件采用已破解或自定义的非标准加密算法。

漏洞风险:使用已破解或非标准的加密算法是很危险的,因为攻击者有可能会破解算法,从而窃取

所保护的数据。

修复或规避建议:采用目前加密领域中加密强度较高的标准加密算法。

示例1:不规范用法

#include "des.h"

using namespace CryptoPP;

int get key(unsigned char[]);//从安全存储中取密钥

int encryptor(charx input, unsigned char output[])

//使用加密强度较低的DES加密算法

unsigned char key[DES::KEYLENGTH];

DESEncryption desEncryptor;

GB/T 34943—2017

int r = get key(key);

desEncryptor.SetKey(key,DES::KEYLENGTH);//设置密钥

desEncryptor.ProcessBlock(input,output);//加密input并保存到output中

return output;

示例2:规范用法之一

#include"aes.h"

using namespace CryptoPP;

int get key(unsigned char[]);//从安全存储中取密钥

int encryptor(char* input, unsigned char output[])

//使用加密强度较高的AES加密算法

unsigned char key[AES::BLOCKSIZE];

AESEncryption aesEncryptor;

unsigned char xorBlock[AES::BLOCKSIZE];

memset(xorBlock,0,AES::BLOCKSIZE);

int r = get key(key);

aesEncryptor.SetKey(key,AES::DEFAULT KEYLENGTH);//设置密钥

aesEncryptor.ProcessAndXorBlock(input,xorBlock,output);//加密input并保存到output中

return output;

6.2.7.6 可逆的散列算法

漏洞描述:软件采用的散列算法具有可逆算法,该算法可利用生成的散列值确定原始输入,或者可

以找到一个输入产生相同的散列值。

漏洞风险:攻击者可通过逆向算法获取原始输入或产生相同散列值的输入,进而绕过依赖散列算法

的安全认证。

修复或规避建议:采用当前公认的不可逆标准散列算法。

示例1:不规范用法

#include"sha.h"

using namespace CryptoPP;

int encryptor(char* input,char* output)//加密函数,输出参数返回加密后的字符串

SHA1 shal;

int r = shal.enc(input,output);//使用SHA1散列加密算法

示例2 :规范用法之一

#include"sha.h"

using namespace CryptoPP;

int encryptor(char* input,char* output) //加密函数,输出参数返回加密后的字符串

GB/T 34943—2017

SHA256 sha256;

int r = sha256.enc(input,output); //使用SHA256 标准散列加密算法

6.2.7.7
密码分组链接模式未使用随机初始化矢量

漏洞描述:密码分组链接模式使用的初始化向量不是一个随机数。

漏洞风险:攻击者有机会通过字典式攻击读取加密的数据。

修复或规避建议:密码分组链接模式使用随机的初始化向量。

示例 1:不规范用法

#include "aes.h"

using namespace CryptoPP;

int key size = 8;

char* encryptor(char* input)

unsigned char key[key size];

unsigned char iv[]={0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08};

·

CBC Mode<AES)::Encryption Encryptor(key,key size,iv);//使用固定的初始化向量

示例2: 规范用法之一

#include<wincrypt.h)

#include "aes.h"

using namespace CryptoPP;

int key size =8;

char* encryptor(char * input)

HCRYPTPROV hcryptprov;

unsigned char key[key size];

unsigned char iv[key size];

… ·

if(CryptGenRandom(hcryptprov,EVP MAX IV LENGTH,iv))//使用随机的初始化向量

CBC Mode<AES>::Encryption Encryptor(key, key size,iv);

6.2.7.8 不充分的随机数

漏洞描述:软件在安全相关代码中依赖不充分的随机数。

漏洞风险:攻击者可以预测将生成的随机数,绕过依赖随机数的安全保护。

GB/T 34943—2017

修复或规避建议:使用目前被业界专家认为较强的经过良好审核的加密
PRNG 算法,初始化随机

数生成器时使用具有足够长度且不固定的种子。

示例1:不规范用法

void example fun()

int i,num;

unsigned char iv[8];

for(i=0;i<8;i++)

num =10*rand()/(RAND MAX+1);//使用不充分的伪随机数生成器

iv[i]=num+0;

示例2: 规范用法之 一

#include<wincrypt.h)

void example fun()

HCRYPTPROV hcryptprov;

unsigned char iv[8];

if(CryptGenRandom(heryptprov,8,iv))//基于加密的伪随机数生成器CSPRNG

6.2.7.9 安全关键的行为依赖反向域名解析

漏洞描述:通过反向域名解析获取IP
地址的域名,然后依赖域名对主机进行身份鉴别。

漏洞风险:攻击者可通过 DNS 欺骗修改 IP
地址与域名的对应关系,从而绕过依赖域名的主机身份

鉴别。

修复或规避建议:通过用户名口令、数字证书等其他手段对主机身份进行鉴别。

示例 1:不规范用法

#include<arpa/inet.h)

#include<winsock.h)

int is trusted(char* address)//验证主机是否值得信任

struct hostent *hp;

char* trustedHost ="trustme.com";

struct in addr myaddress;

myaddress,s addr = inet addr(address);//将address转换成32位Ipv4地址

//通过反向解析获取myaddr地址的域名

hp = gethostbyaddr((char )&.myaddress.s addr,sizeof(in addr),AF INET);

//通过域名对主机进行身份鉴别

GB/T 34943—2017

//攻击者可通过 DNS 欺骗绕过依赖域名的主机身份鉴别

if(hp&.&. ! strncmp(hp->h name,trustedHost, sizeof(trustedHost)))

return 1;

else

return 0;

示例2: 规范用法之一

int is true(char*,charx);//判断用户名口令是否正确,是则返回1,否则返回0

int is trusted(char* username, char* password)//验证主机是否值得信任

{

//通过用户名口令对主机进行身份鉴别

return is true(username, password);

6.2.7.10 没有要求使用强口令

漏洞描述:软件没有要求用户使用具有足够复杂度的口令。

漏洞风险:攻击者可以很容易地猜出用户的口令或实施暴力破解攻击。

修复或规避建议:要求用户使用具有足够复杂度的口令。口令强度策略应包含下列属性:

— 最小和最大长度;

——包含字母、数字和特殊字符;

- — 不包含用户名;

——定期更改口令;

——不使用用过的口令;

——身份鉴别失败一定次数后锁定用户。

1:不规范用法

void set password(string);//存储用户输入的口令

void init user(string username, string password)

set password(password);//口令强度可能不足

示例2: 规范用法之一

string username;//用户名

string[] passwordlist; //口令表

string create password date; //口令创建的时间

int password outdate days;//口令过期天数(可配置)

boolean user exists(string,string);//判断用户名口令是否正确

void set password(string); //存储用户输入的口令

GB/T 34943—2017

int check length(string); //口令长度检测,符合要求返回1,否则返回0

int check mode(string); //口令是否包含字母,数字和特殊字符,缺少其中一种或以上表示口令强度弱

//全部包含返回1,否则返回0

int check exclude name(string); //口令是否不包含用户名,不包含返回1,否则返回0

int check time(string); //通过比较当前时间和口令创建时间判断口令是否过期

//未过期返回1,否则返回0

int check is used(string); //通过查询口令表判断口令是否曾经使用过,未使用过返回1,否则返回0

···

int check password level(string password) // 口令强度检测

if(check length(password)==0)

cout<<" 口令长度不符合要求!"<<endl;

return 0;

if(check mode(password)==0)

cout<<" 口令组合等级弱!"<<endl;

return 0;

if(check exclude name(password)==0)

cout<<" 口令包含用户名!"<<endl;

return 0;

if(check is u sed(password)==0)

cout<<" 口令曾经使用过!"<<endl;

return 0;

return 1;

void init u ser(string username,string password){

if(check password level(password)) //检测 password 的口令强度

set password(password);

else

//用户登录时自动判断密码使用期限并提示用户更新密码

GB/T 34943—2017

void check user(string username, string password)

if(user exists(username,password)) //身份鉴别

if(!check time(password))//检测password是否过期

//提示用户密码已过期,建议其修改密码

··

else

6.2.7.11 没有对口令域进行掩饰

漏洞描述:用户输入口令时没有对口令域进行掩饰。

漏洞风险:增加了攻击者通过观察屏幕获取到口令的可能性。

修复或规避建议:用户输入口令时对口令域进行掩饰。通常,用户输入的每一个字符都应该以星号

形式回显。

1:不规范用法

void example fun()

char password[MAX STR LEN];//MAX STR LEN的值为15

inti=0;

charc=*0;

printf("Please enter the password:");

while(i<MAX STR LEN &.&.c!=\n)

scanf("%c",&.c);//没对用户输入的口令进行掩饰

password[i]= c;

i++;

示例2: 规范用法之 一

void example fun()

{

char password[MAX STR LEN];//MAX STR LEN的值为15

inti=0;

char c=0;

printf("Please enter the password:");

while(i<MAX STR LEN &.&. (c=getch())!=\n)

GB/T 34943—2017

password[i]= c;

putchar(*);//用星号代替用户所输入的口令

i++;

6.2.7.12 通过用户控制的 SQL
关键字绕过授权

漏洞描述:软件使用的数据库表其中包括了某个用户不应有权访问的记录,但该软件执行的一个

SQL 语句中的关键字却可以受该用户控制。

漏洞风险:如果用户可以将关键字设置为任何值,那么该用户就可以修改该关键字指向未经授权的

记录。

修复或规避建议:对用户输入的关键字进行验证,确保其只能访问该用户有权访问的记录。

示例 1:不规范用法

#include<stdio.h>

#include<string.h)

char username[16];//用户名

·

int sql compare(char*);//判断字符串是否符合构建sql语句的要求,是则返回1,否则返回0

void sqlquery(char* staffID) //staffID为用户输入数据,不超过10个字符

if(sql compare(staffID))

char sqlQuery[64]="SELECT* FROM employee WHERE staffID='";

strcat(sqIQuery,staffID);//用户输入的staffID可能不在其访问权限内

streat(sqIQuery,"");

//在数据库中执行sqlQuery语句

示例2 :规范用法之一

#include<stdio.h)

#include<string.h)

char username[16];//用户名

int sql compare(char*);//判断字符串是否符合构建sql语句的要求,是则返回1,否则返回0

char* find departID(char*);//根据用户名返回其所在部门的部门ID

void sql query(char* staffID)//staffID为用户输入数据,不超过10个字符

if(sql compare(staffID))

//查询语句增加部门ID查询条件

char sqlQuery[64]="SELECT FROM employee WHERE staffID=";

GB/T 34943—2017

strcat(sqlQuery, staffID);

strcat(sqIQuery,"and DepartID='");

strcat(sqlQuery, find departID(username));

streat(sqIQuery,"");

//在数据库中执行sqIQuery语句

6.2.7.13 未使用盐值计算散列值

漏洞描述:软件针对口令等不应可逆的输入使用了单向加密散列,但未使用盐值。

漏洞风险:如果未使用盐值计算散列值,攻击者就更容易利用彩虹表等字典攻击技术破解口令。

修复或规避建议:使用盐值计算散列值,增加攻击者破解口令的难度。

示例 1:不规范用法

#include "sha.h"

using namespace CryptoPP;

int encryptor(char* input,char* output)//加密函数,输出参数返回加密后的字符串

SHA256 sha256;

int r = Sha256.enc(input,output);

void example fun(char* password)//password最大长度为20个字符

char psw[1024]={0};

intr = encryptor(password,psw);//仅使用单向加密,还是容易被攻击者用彩虹表等方式破解口令

//将加密得到的psw字符串存储到数据库中

示例2: 规范用法之 一

#include "sha.h"

#include "aes.h"

using namespace CryptoPP;

int encryptor(char* input,char* output)//加密函数,输出参数返回加密后的字符串

SHA256 sha256;

int r = Sha256.enc(input, output);

· ·

void send salt(char* salt)//用AES算法加密盐值后传输到另一台服务器上

AESEncryption aesEncryptor;

GB/T 34943—2017

char output[1024]={0};

int r = aesEncryptor.enc(salt, output);

//发送加密后盐值(output)到另一台服务器上

·

char* random str(int);//随机生成字符串

int saltLength = 20;

void example fun(char* password)//password最大长度为20个字符

char* salt = random str(saltLength);//获得一个长度为saltLength的随机字符串

char str[64];

strcat(str,password);

strcat(str,salt); //加入salt值

char psw[1024]={0};

int r= encryptor(str,psw);//为攻击者破解口令增加难度

//将加密得到的psw字符串存储到数据库中

//将salt字符串加密后存储到另一台服务器的数据库中

send salt(salt);

6.2.7.14 RSA
算法未使用最优非对称加密填充

漏洞描述:使用RSA 加密算法时未使用最优非对称加密填充。

漏洞风险:未使用最优非对称加密填充将降低攻击者解密的难度。

修复或规避建议:使用RSA 加密算法时使用最优非对称加密填充。

示例 1:不规范用法

#include "rsa.h"

using namespace CryptoPP;

int encryptor(char* input,char* output)//加密函数,输出参数返回加密后的字符串

RSAES PKCS1v15 Encryptor rsapkcsl;//使用Pkcs1填充

int r = rsapkesl.enc(input, output);

示例2: 规范用法之一

#include"rsa.h"

using namespace CryptoPP;

int encryptor(char input,char* output)//加密函数,输出参数返回加密后的字符串

RSAES OAEP SHA Encryptor rsaoaep; //使用OAEP加密填充

int r= rsaoaep.enc(input, output);

GB/T 34943—2017

6.2.8 Web 问题

6.2.8.1 跨站脚本

漏洞描述:使用未经验证的输入数据构建 Web 页面。

漏洞风险:攻击者可构建任意 Web 页面,并在页面中植入恶意脚本。

修复或规避建议:在构建 Web
页面前对输入数据进行验证或编码,确保输入数据不影响页面的

结构。

示例 1:不规范用法

#include<Winlnet.h)

void write html(const charx,const char*);

int example fun(int argc,char ** argv)

//创建一个Internet连接

HINTERNET example =

NULL,NULL,0);

//将参数1的字符串写入参数2指定网页的函数

InternetOpen("TextExample",INTERNET OPEN TYPE PRECONFIG,

char name = getPar(argv,'name);//name来源于默认为不可信任的外部输入

write html(name,"index.html");//name在输出前未经验证,若攻击者输入恶意脚本即可篡改index.html

InternetCloseHandle(example); //关闭Internet连接

return 0;

2 :规范用法之 一

#include<WinInet.h)

void write html(const char×,const char*);//将参数1的字符串写入参数2指定网页的函数 char * verification(const char *);//验证参数,若参数不合法则转义成合法字符串后返回

int example fun(int argc,char * argv)

//创建一个Internet连接

HINTERNET example = InternetOpen("TextExample",INTERNET OPEN TYPE PRECONFIG,

NULL,NULL,0);

……

char * name = getPar(argv,'name);//name来源于默认为不可信任的外部输入

write html(verification(name),"index.html");//name在输出前已进行验证或转义

InternetCloseHandle(example);//关闭Internet连接

return 0;

GB/T 34943—2017

A

(资料性附录)

C/C++ 语言源代码漏洞测试案例

A.1 范围

本案例为第三方机构的测试人员利用自动化静态分析工具开展的 C++
语言源代码漏洞测试案 例。本次测试选择C++
语言开发的开源密码学库"Crypto++Library" (版本号5.2.1)共60765行源

代码进行测试。

A.2 测试依据

GB/T 34943—2017《C/C++语言源代码漏洞测试规范》。

A.3 测试目的

本次测试的目的如下:

a) 指导GB/T
34943—2017《C/C++语言源代码漏洞测试规范》的读者理解该标准;

b) 发现及定位软件源代码中的漏洞。

A.4 测试过程

本案例的测试过程包括测试策划、测试设计、测试执行和测试总结四个阶段。

A.4.1 测试策划

A.4.1.1 确定测试工具

本项目将采用 Checkmarx CxEnterprise 工具进行测试。

A.4.1.2 确定测试环境

本项目采用的测试工具不依赖被测源代码的开发环境,只需要将被测源代码传到测试工具所在的

计算机即可,测试环境为测试工具安装的环境。

A.4.1.3 分析与评估测试风险并制定应对措施

本项目存在以下风险:

a) 测试工具无法正常对被测源代码进行扫描。

应对措施:查看测试工具记录的日志,查找问题原因,若无法找到问题原因,则联系测试工具厂

商提供技术支持。

b) 由于技术问题等原因导致实际进度滞后于计划进度。

应对措施:若实际进度滞后于计划进度,则在人工分析时增加人员进行测试结果分析。

GB/T 34943—2017

A.4.1.4 制定测试进度计划

本项目的测试进度安排见表 A.1。

A.1 Crypto++Library 源代码漏洞测试进度安排表

测试阶段

人员角色

职 责

时间(工作日)

工作成果

测试策划

测试项目负责人

负责项目的组织管理、资源保障 和过程评审,明确项目规划,制

定测试进度计划

1

《测试计划》

测试设计

测试设计员

开展测试需求分析,确定测试内 容、测试方法、测试环境和测试

工具,编写测试用例

3

《测试说明》

测试执行

测试员

执行测试,记录测试过程和结果

1

《测试日志》

测试分析员

人工分析测试结果

2

测试总结

测试项目负责人

对整个源代码漏洞测试过程进

行总结

2

《测试总结报告》

A.4.1.5 形成测试计划

整理以上A.4.1.1~A.4.1.4 的内容,形成《测试计划》文档。

A.4.1.6 评审测试策划

组织管理层对该项目的测试策划进行评审,评审结果如下:

a) 测试计划明确了测试需要的工具和环境,测试实施条件要素考虑全面合理;

b) 测试计划明确的测试人员分工和进度计划具有可实施性;

c) 测试计划中的测试风险分析全面合理,且具有可行的应对风险的措施。

A.4.2 测试设计

A.4.2.1 分析测试需求

Crypto++Library 是 C++
语言开发的开源密码学库,与软件安全功能相关。由于该软件是开源

代码,容易导致安全攻击。因此,本次将重点针对‘安全功能'类14个源代码漏洞指标进行测试。

A.4.2.2 确定测试内容

根据以上测试需求分析,本项目将对以下C++ 语言源代码漏洞进行测试:

安全功能:

a) 明文存储口令;

b) 存储可恢复的口令;

c) 口令硬编码;

d) 敏感信息明文传输;

e) 使用已破解或危险的加密算法;

f) 可逆的散列算法;

g) 密码分组链接模式未使用随机初始化矢量;

GB/T 34943—2017

h) 不充分的随机数;

i) 安全关键的行为依赖反向域名解析;

j) 没有要求使用强口令;

k) 没有对口令域进行掩饰;

1) 通过用户控制的 SQL 关键字绕过授权;

m) 未使用盐值计算散列值;

n) RSA 算法未使用最优非对称加密填充。

A.4.2.3 确定测试方法

本项目将首先采用自动化静态分析工具对被测源代码进行漏洞扫描,然后人工分析自动化静态分

析工具的扫描结果,筛除误报的源代码漏洞。

A.4.2.4 明确测试工具

本项目采用的自动化静态分析工具名称和版本号为"Checkmarx CxEnterprise
6.2.0"。

A.4.2.5 明确测试环境

本项目的测试环境见表 A.2。

A.2 Crypto++Library 源代码漏洞测试环境

硬件环境

软件环境

设备编号

名称型号

配置(CPU/内存/硬盘/ …)

H-620

惠普8560w移动工作站

Intel Core i7-2720QM(2.2 GHz)/

16G/750G

Windows 7 Professional中文版(64位)

SQL Server 2008 Express Edition(64位)

IIS 7

IE8

Checkmarx CxEnterprise 6.2.0(测试工具)

A.4.2.6 设计测试用例

本项目的测试用例见表 A.3。

A.3 Crypto++Library 源代码漏洞测试用例

测试用例编号

YMLD-YL-2016-1001-0001

测试用例名称

Crypto++Library源代码漏洞测试用例

编号

测试内容、测试过程和测试方法

期望结果

1

使用IE8浏览器打开Checkmarx CxEnterprise 6.2.0

显示测试工具的登录页面

2

在"登录"页面中输入用户名(administrator@cx)和密码(Sb3396981

*×*),点击“登录”按钮

成功登录工具页面

3

在工具页面中选择"安全功能"类的"明文存储口令"指标进行测试

明确该源代码是否存在"明文存储

口令"指标的漏洞

其余13个指标的测试内容、测试过程和测试方法同上,此处略

测试用例设计人员

测试用例设计日期

××××- ××- ××

GB/T 34943—2017

A.4.2.7 形成测试说明

整理以上 A.4.2.1~A.4.2.6 的内容,形成《测试说明》文档。

A.4.2.8 评审测试设计

组织管理层对该项目的测试设计进行评审,评审结果如下:

a) 测试需求分析合理;

b) 测试内容和方法符合测试需求;

c) 测试用例的操作步骤和输入数据详细、正确、可实施;

d) 测试用例的期望结果描述准确;

e) 测试人员、环境和工具齐备并符合要求。

A.4.3 测试执行

A.4.3.1 执行测试并记录测试过程和结果

根据测试用例执行测试,测试记录见表 A.4。

A.4 Crypto++Library 源代码漏洞测试记录

测试记录编号

YMLD-JL-2016-1001-0001

测试用例名称

Crypto++Library源代码漏洞测试记录

测试过程

编号

测试内容、测试过程和测试方法

实际结果

1

使用IE8浏览器打开Checkmarx CxEnterprise 6.2.0

打开测试工具的登录页面

2

在"登录"页面中输入用户名(administrator@cx)和密码(Sb3396981

***),点击“登录”按钮

登录至测试工具的主页面

3

在工具页面中选择"安全功能”类的“明文存储口令"指标进行测试

未发现"明文存储口令"源代码

漏洞

其余13个指标的测试内容、测试过程和测试方法同上,此处略

发现其余13个指标共116个源代

码漏洞

测试执行人员

测试执行日期

××××- ×X- ××

A.4.3.2 分析测试结果

通过人工分析发现,自动化静态分析工具由于不识别部分加密函数导致出现7个误报,误报的源代

码漏洞已在自动化静态分析工具中进行了标记和说明。

A.4.3.3 形成测试日志

整理以上 A.4.3.1 和 A.4.3.2 的内容,形成《测试日志》文档。

A.4.3.4 评审测试执行

组织管理层对该项目的测试执行进行评审,评审结果如下:

a) 测试用例执行已达到100%;

GB/T 34943—2017

b) 操作结果真实有效;

c) 操作结果描述清晰、准确;

d) 本次测试未出现与预期结果不一致的操作结果;

e) 经复核,人工分析的结果正确。

A.4.4 测试总结

A.4.4.1 编制测试总结报告

在本次测试项目周期内,对 Crypto++Library 项目60765行源代码,依据 GB/T
34943—2017

《C/C++
语言源代码漏洞测试规范》,采用自动化静态分析工具扫描和人工分析相结合的方法,进行源

代码漏洞测试。本次源代码漏洞测试的测试内容和结论如下:

本次源代码漏洞采用"Checkmarx CxEnterprise
6.2.0"测试工具,对明文存储口令、存储可恢复的 口令等14种 C++
语言源代码漏洞进行了扫描,共扫描出116个源代码漏洞。经人工对漏洞进行分
析,发现部分加密函数来源于第三方可执行代码库,自动化静态分析工具由于不识别这些函数导致出现

7个误报。筛除误报后仍存在109个源代码漏洞。本次测试的详细测试结果见表
A.5。

A.5 Crypto++Library 源代码漏洞测试结果

序号

测试内容

测试结果

备注

1

明文存储口令

未发现漏洞

其余13个指标内容略

发现其余13个指标共109个源代

码漏洞

源代码漏洞的详情可到自动化静

态分析工具中查看

A.4.4.2 评审测试总结

组织管理层对该项目的测试总结进行评审,评审结果如下:

a) 测试需求和测试目标已完成;

b) 测试结论能够追溯到测试结果;

c) 已具备测试准出条件;

d) 测试过程中风险规避合理。 注:本案例相关内容的格式仅供参考。

GB/T 34943—2017

B

(资料性附录)

C/C++ 语言源代码漏洞类别与名称

为方便读者查阅本标准的源代码漏洞,以下按本标准漏洞出现的顺序列出了本标准所有漏洞的类

别和名称:

a) 行为问题

不可控的内存分配。

b) 路径错误

不可信的搜索路径。

c) 数据处理

1) 相对路径遍历;

2) 绝对路径遍历;

3) 命令注入;

4) SQL 注入;

5) 进程控制;

6) 缓冲区溢出;

7) 使用外部控制的格式化字符串;

8) 整型溢出;

9) 信息通过错误消息泄露;

10) 信息通过服务器日志文件泄露;

11) 信息通过调试日志文件泄露;

12) 未检查的输入作为循环条件。

d) 错误的 API 协议实现 堆检查。

e) 劣质代码

敏感信息存储于上锁不正确的内存空间。

f) 不充分的封装

公有函数返回私有数组。

g) 安全功能

1) 明文存储口令;

2) 存储可恢复的口令;

3) 口令硬编码;

4) 敏感信息明文传输;

5) 使用已破解或危险的加密算法;

6) 可逆的散列算法;

7) 密码分组链接模式未使用随机初始化矢量;

8) 不充分的随机数;

9) 安全关键的行为依赖反向域名解析;

10) 没有要求使用强口令;

11) 没有对口令域进行掩饰;

12) 通过用户控制的SQL 关键字绕过授权;

GB/T 34943—2017

13) 未使用盐值计算散列值;

14) RSA 算法未使用最优非对称加密填充。

h) Web 问 题 跨站脚本。

style="width:3.11331in" />GB/T 34943—2017

总结

更多内容 可以 点击 访问 siduwenku.com 网站的报告 进一步学习

联系我们

DB13-T 5794-2023 毛皮碎料加工技术规范 河北省.pdf